#include "lib-runtime.hpp"

vector<call_info> calls_stack;
vector<call_info> calls_list;

call_info aux;
fstream out;
string file = "trace/dynamic_trace";

int glob_call_num = 0;

// surcharge de << pour l'affichage des infos relatives à un appel de fonction
ostream& operator << (ostream & out, const call_info item)
{
	out << "Call number : " << item.num_appel << endl;
	out << "Required : " << item.required << endl;
	out << "Function name : " << item.nom << endl;	
	out << "Entry time (microseconds) : " << item.entry_us << endl;
	out << "Exit time (microseconds) : " << item.exit_us << endl;
	return out;
}

// affichage d'un appel de fonction
void display_vec(vector<call_info> &v)
{
	if (!v.empty())
	{
		for_each(v.begin(), v.end(),
			[](call_info c)
			{
				cout << "-----" << endl;
				cout << c;
			}
		);
	}
	else
		cout << "Vector is empty." << endl;
}


// mise à jour de la struct contenant les infos relatives à un appel de fonction
void enter_function(const char * func_name, const char * required)
{	
	
	aux.required = (strcmp(required, "oui")==0);	
	aux.num_appel = glob_call_num;
	aux.nom = func_name;
	gettimeofday(&aux.entry_time, 0);
	aux.exit_time.tv_sec = 0;
	aux.exit_time.tv_usec = 0;
	aux.entry_us = 0;
	aux.exit_us = 0;
	calls_stack.push_back(aux);
	++glob_call_num;
	
	
	// cas du main : ouverture en écriture du fichier de traces dynamiques 
	if(strcmp(func_name, "main")==0)
	{
		out.exceptions(ifstream::failbit|ifstream::badbit);
		try
		{
			out.open(file, ifstream::out);
		}
		catch(ifstream::failure e)
		{
			cerr << "[erreur] " << e.what() << endl;
			exit(1);
		}	
	}
}

// insère les données recueillies dans un vecteur
void exit_function(const char *  func_name)
{
	// recupère le dernier élément de la pile
	// et ajoute les timestamps d'entrée et de sortie
	aux = calls_stack.back();
	gettimeofday(&aux.exit_time,0);
	aux.entry_us = aux.entry_time.tv_sec * 1000000 + aux.entry_time.tv_usec;	
	aux.exit_us = aux.exit_time.tv_sec * 1000000 + aux.exit_time.tv_usec;
	
	// pop la pile
	calls_stack.pop_back();
	
	// insert dans la liste
	calls_list.push_back(aux);
	
	// CAS DU MAIN : écriture des données contenues dans le vecteur
	// et fermeture du fichier en écriture
	if(strcmp(func_name, "main")==0)
	{
		sort(calls_list.begin(), calls_list.end(), 
			[](const call_info &c1, const call_info &c2)
			{ 
				return c1.num_appel < c2.num_appel;
			}
		);
		
		out.exceptions(ifstream::failbit|ifstream::badbit);
		try
		{
			for_each(calls_list.begin(), calls_list.end(),
				[](call_info c)
				{
					out<< "Call " << c.num_appel << " required " << c.required << " function " << c.nom << " entry " << c.entry_us << " exit " << c.exit_us << endl;
				}
			);
			out.close();	
		}
		catch(ifstream::failure e)
		{
			cerr << "[erreur] " << e.what() << endl;
			exit(1);
		}
		
		// affichage du résultat intermédiaire dans le terminal
		display_vec(calls_list);
	}	
}





